/*
 *   Copyright (c) 2010-2022, SIUFUNG
 */
package net.siufung.market.base.user.controller;

import cn.hutool.core.date.SystemClock;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.StyleSet;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.siufung.core.model.EnumsVo;
import net.siufung.core.model.enums.DeletedEnum;
import net.siufung.core.page.PagerResult;
import net.siufung.core.result.Result;
import net.siufung.core.result.ResultFail;
import net.siufung.core.result.ResultOk;
import net.siufung.core.utils.CopyUtil;
import net.siufung.market.base.user.controller.assembler.UserAssembler;
import net.siufung.market.base.user.controller.model.dto.UserDto;
import net.siufung.market.base.user.controller.model.dto.UserSaveDto;
import net.siufung.market.base.user.controller.model.dto.UserUpdateDto;
import net.siufung.market.base.user.controller.model.dto.page.UserPageDto;
import net.siufung.market.base.user.controller.model.vo.UserExcelVo;
import net.siufung.market.base.user.controller.model.vo.UserVo;
import net.siufung.market.base.user.controller.regulation.UserCreateRegulation;
import net.siufung.market.base.user.controller.regulation.UserDeleteRegulation;
import net.siufung.market.base.user.controller.regulation.UserUpdateRegulation;
import net.siufung.market.base.user.enums.UserSexes;
import net.siufung.market.base.user.mapper.IUserDetailMapper;
import net.siufung.market.base.user.mapper.IUserMapper;
import net.siufung.market.base.user.mapper.entity.User;
import net.siufung.market.base.user.mapper.entity.UserDetail;
import net.siufung.market.base.user.api.IUserDeptApi;
import net.siufung.market.base.user.api.dto.UserDeptDto;
import net.siufung.market.base.user.service.IUserService;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 系统用户表 前端控制器
 *
 * @author 陈建峰
 * @since 2022-07-05 16:14:50
 */
@Api(tags = "用户管理")
@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping("/sys/user")
public class UserController {

    private final IUserService userService;
    private final IUserMapper userMapper;
    private final IUserDeptApi userDeptApi;

    private final IUserDetailMapper userDetailMapper;

    /**
     * 通过主键获取 系统用户表
     * @param id 主键
     * @return Result<UserVo>
     * */
    @ApiOperation(value = "通过Id获取系统用户表信息")
    @GetMapping(value = "/id/{id}")
    public Result<UserVo> getById(
            @PathVariable("id") Integer id) {
        return Result.ok(
            UserAssembler.from(
                    userMapper.selectById(id),
                    userDetailMapper.selectOne(new LambdaQueryWrapper<UserDetail>()
                            .eq(UserDetail::getUserId, id))));
    }

    /**
     * 获取 系统用户表列表
     * @param userDto 属性
     * @return Result<List<UserVo>>
     * */
    @ApiOperation(value = "获取系统用户表列表")
    @PostMapping(value = "/list")
    public Result<List<UserVo>> list(
            @RequestBody UserDto userDto) {
        return Result.ok(
            UserAssembler.fromList(userMapper.selectList(Wrappers.query(userDto.to()))));
    }

    /**
     * 获取 系统用户表分页
     * @param userPageDto 属性
     * @return 查询分页结果
     * */
    @ApiOperation(value = "获取系统用户表分页")
    @PostMapping(value="/page")
    public Result<PagerResult<UserVo>> getPage(
            @RequestBody UserPageDto userPageDto) {
        userPageDto.validated();
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(
                !Strings.isNullOrEmpty(userPageDto.getMobile()), User::getMobile, userPageDto.getMobile());
        wrapper.lambda().like(
                !Strings.isNullOrEmpty(userPageDto.getUserName()), User::getUserName, userPageDto.getUserName());
        if(!Strings.isNullOrEmpty(userPageDto.getDeptId()) && Objects.nonNull(userDeptApi)){
            List<String> childDeptIdList = userDeptApi.getChildDeptIdList(userPageDto.getDeptId());
            wrapper.lambda()
                    .in(CollectionUtils.isNotEmpty(childDeptIdList), User::getDeptId, childDeptIdList);
        }
        wrapper.lambda().orderByDesc(User::getCreatedAt);
        IPage<User> userPage = userMapper.selectPage(
                new Page<>(userPageDto.getPageNo(), userPageDto.getPageSize()), wrapper);
        PagerResult<UserVo> userVoPage = new PagerResult<>(
                userPage.getCurrent(), userPage.getSize(), userPage.getTotal());
        List<User> userRecords = userPage.getRecords();
        Integer[] userIdList = userRecords.stream()
                .map(User::getId).distinct().toArray(Integer[]::new);
        List<UserDetail> userDetailList = Lists.newArrayList();
        if(ArrayUtil.isNotEmpty(userIdList)){
            userDetailList = userDetailMapper.selectList(
                    new LambdaQueryWrapper<UserDetail>().in(UserDetail::getUserId,
                            Lists.newArrayList(userIdList)));
        }
        String[] userDeptIdList = userRecords.stream()
                .map(User::getDeptId).distinct().toArray(String[]::new);
        List<UserDeptDto> userDeptDtoList = Lists.newArrayList();
        if(Objects.nonNull(userDeptApi) && ArrayUtil.isNotEmpty(userDeptIdList)){
            userDeptDtoList = userDeptApi.getDeptList(userDeptIdList);
        }
        userVoPage.setRecords(
            UserAssembler.fromList(userRecords, userDetailList, userDeptDtoList));
        return Result.ok(userVoPage);
    }

    /**
     * 通过主键删除 系统用户表 对象
     * @param id 主键
     * @return 删除结果
     * */
    @ApiOperation(value = "删除系统用户表对象")
    @PostMapping(value="/delete/{id}")
    public Result<Void> deleteById(
        @PathVariable("id") Integer id) {
        UserDeleteRegulation userDeleteRegulation = new UserDeleteRegulation(userMapper);
        userDeleteRegulation.isSatisfiedBy(id);
        if(userService.removeById(id)){
            return Result.ok(ResultOk.REMOVE);
        }
        return Result.fail(ResultFail.DATA_REMOVE_ERROR);
    }

    /**
     * 创建 系统用户表
     * @param userSaveDto 对象属性
     * @return 创建结果
     * */
    @ApiOperation(value = "创建 系统用户表")
    @PostMapping(value="/create")
    public Result<Void> create(
            @RequestBody UserSaveDto userSaveDto) {
        userSaveDto.validated();
        UserCreateRegulation userCreateRegulation = new UserCreateRegulation(userMapper);
        userCreateRegulation.isSatisfiedBy(userSaveDto);
        if(userService.save(userSaveDto.to(), userSaveDto.toDetail(),
                userSaveDto.getRoleIds())){
            return Result.ok(ResultOk.ADD);
        }
        return Result.fail(ResultFail.DATA_ADD_ERROR);
    }


    /**
     * 更新 系统用户表
     * @param userUpdateDto 对象属性
     * @return Result<Void>
     * */
    @ApiOperation(value = "更新 系统用户表 信息")
    @PostMapping(value="/update")
    public Result<Void> update(
            @RequestBody UserUpdateDto userUpdateDto) {
        userUpdateDto.validated();
        User userOf = userService.getById(userUpdateDto.getId());
        CopyUtil.copyPropertiesIgnoreNull(userUpdateDto.to(), userOf);
        UserUpdateRegulation userUpdateRegulation = new UserUpdateRegulation(userMapper);
        userUpdateRegulation.isSatisfiedBy(userUpdateDto);
        if(userService.updateById(userOf, userUpdateDto.toDetail(),
                userUpdateDto.getRoleIds())){
            return Result.ok(ResultOk.UPDATE);
        }
        return Result.fail(ResultFail.DATA_UPDATE_ERROR);
    }

    /**
     * 更新 系统用户表 状态
     * @param id 主键
     * @param deleted 数据状态
     * @return Result<Void>
     * */
    @ApiOperation(value = "更新 系统用户表 状态")
    @PostMapping(value="/status/{id}/{deleted}")
    public Result<Void> updateStatusById(
            @PathVariable("id") Integer id,
            @PathVariable("deleted") boolean deleted) {
        if(userService.updateStatusById(id, DeletedEnum.get(deleted))){
            return Result.ok(ResultOk.STATUS);
        }
        return Result.fail(ResultFail.DATA_UPDATE_ERROR);
    }

    /**
     * 获取用户性别列表
     * @return Result<List<EnumsVo>>
     * */
    @ApiOperation(value = "获取用户性别列表")
    @GetMapping(value = "/getUserSexList")
    public Result<List<EnumsVo>> getUserSexList() {
        return Result.ok(UserSexes.getList());
    }


    /**
     * 导出用户数据
     * @param response 请求
     */
    @ApiOperation(value = "导出用户数据")
    @PostMapping(value = "/exportExcel")
    public void export(
            HttpServletResponse response) {
        ExcelWriter writer = ExcelUtil.getWriter();
        Map<String,String> headerMap = new LinkedHashMap<>();
        Object[][] exportInfo = {
                {"id","ID",24},
                {"userName","用户名称",32}
        };
        for (int i = 0; i < exportInfo.length; i++) {
            Object[] item = exportInfo[i];
            headerMap.put(item[0].toString(), item[1].toString());
            writer.setColumnWidth(i, Integer.parseInt(item[2].toString()));
        }
        Font font = writer.createFont();
        font.setFontHeightInPoints((short) 12);
        font.setFontName("宋体");

        StyleSet style = writer.getStyleSet();
        style.setAlign(HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
        style.setFont(font,false);

        writer.setHeaderAlias(headerMap);
        writer.setOnlyAlias(true);

        List<User> userList = userMapper.selectList(Wrappers.query());
        List<UserExcelVo> userExcelVoList = UserAssembler.fromListForExcel(userList);
        writer.write(userExcelVoList, true);

        try {
            response.setCharacterEncoding(CharsetUtil.UTF_8);
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition",
                    "attachment;filename=" + URLEncoder.encode(String.valueOf(SystemClock.now()), "UTF-8") + ".xls");
            ServletOutputStream out = response.getOutputStream();
            writer.flush(out, true);
            writer.close();
            IoUtil.close(out);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}